import {
  Body,
  Controller,
  Delete,
  Get,
  Inject,
  Param,
  Post,
  Query,
  Req,
  Sse,
  UnauthorizedException,
} from '@nestjs/common';
import { NotifyService } from './notify.service';
import { Observable, Subject } from 'rxjs';
import { SubjectManager } from './subjects';
import { SkipLogin } from 'src/common/decorator/public.decorator';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
import { getRedisKey } from 'src/utils';

/*
    用户订阅消息 - 1. 首次登录；2. 切换窗口后重新连接

    给指定用户发消息 - 1. 数据入mysql；2. 直接发送

    广播  - 1. 1000条通知一个人 - insert分批入库 - 发送消息
            - 2. 1条通知1000个人 - save入库 - 队列发送消息减少并发
*/
@Controller('notify')
export class NotifyController {
  constructor(
    @Inject(CACHE_MANAGER) private cacheManager: Cache,
    private readonly notifyService: NotifyService,
  ) {}

  /**
   * 订阅通知，通过query传递receiver_id
   *
   * @param {*} query
   * @return {*}  {Promise<Observable<any>>}
   * @memberof NotifyController
   */
  @SkipLogin()
  @Get('common')
  @Sse()
  async subEvents(@Query() query: any): Promise<Observable<any>> {
    const { id: clientId } = query || {};
    const redisKey = getRedisKey(clientId, 'user', 'info');
    if (!clientId) throw new UnauthorizedException();
    const exist = await this.cacheManager.store.get(redisKey);
    if (!exist) throw new UnauthorizedException();

    // 检查是否已经存在连接，如果存在则先清理
    let stream = SubjectManager.SseSubject.get(clientId);
    if (stream) {
      // 清理旧连接
      SubjectManager.SseSubject.delete(clientId);
    }

    // 创建新的Subject
    stream = new Subject<any>();
    SubjectManager.SseSubject.set(clientId, stream);

    // 设置心跳定时器
    const heartbeatInterval = setInterval(() => {
      // 发送心跳消息到客户端，同时更新活动时间
      if (!stream.closed) {
        stream.next('heartbeat');
        SubjectManager.updateActivity(clientId);
      }
    }, 1000 * 30); // 每30秒发送一次心跳

    // 将心跳定时器关联到连接
    SubjectManager.setHeartbeatTimer(clientId, heartbeatInterval);

    // 延迟发送未读通知数量
    const notifyTimer = setTimeout(() => {
      if (!stream.closed) this.notifyService.getUnReadCount(clientId);
    }, 1000 * 3);

    // 当客户端断开连接时清理资源
    return new Observable<any>((subscriber) => {
      const subscription = stream.subscribe({
        next: (data) => {
          // 更新活动时间
          SubjectManager.updateActivity(clientId);
          subscriber.next(data);
        },
        error: (err) => subscriber.error(err),
        complete: () => subscriber.complete(),
      });

      return () => {
        // 清理通知定时器
        clearTimeout(notifyTimer);

        // 清理订阅
        if (subscription && !subscription.closed) {
          subscription.unsubscribe();
        }

        // 清理Subject和相关资源（包括心跳定时器）
        SubjectManager.SseSubject.delete(clientId);
      };
    });
  }

  // 获取通知列表
  @Get()
  async getNotifyList(@Req() req: any) {
    const { pageSize = 10, pageNo = 1, isShort = false } = req.query;
    const paginateOptions = isShort
      ? { limit: 5, page: 1 }
      : { limit: pageSize, page: pageNo };
    const { userId = '' } = req.user || {};
    return await this.notifyService.findAll(paginateOptions, userId);
  }

  // 获取通知详情
  @Get(':id')
  async getNotifyDetail(@Param('id') id: string, @Req() req: any) {
    const { userId } = req.user || {};
    return await this.notifyService.findOne(+id, userId);
  }

  // 获取上一条消息ID
  @Get(':id/prev')
  async getPrevNotifyId(@Param('id') id: string, @Req() req: any) {
    const { userId } = req.user || {};
    return await this.notifyService.getPrevNotifyId(+id, userId);
  }

  // 获取下一条消息ID
  @Get(':id/next')
  async getNextNotifyId(@Param('id') id: string, @Req() req: any) {
    const { userId } = req.user || {};
    return await this.notifyService.getNextNotifyId(+id, userId);
  }

  // 删除一条通知
  @Delete(':id')
  async deleteNotify(@Param('id') id: string, @Req() req: any) {
    const { userId } = req.user || {};
    await this.notifyService.remove(+id, userId);

    return '操作成功';
  }

  // 清空所有未读
  @Post('clear-read')
  async clearUnRead(@Req() req: any) {
    const { userId } = req.user || {};
    await this.notifyService.clearRead(userId);

    return '操作成功';
  }

  // 清空通知列表
  @Post('clear')
  async clearNotify(@Req() req: any) {
    const { userId } = req.user || {};
    await this.notifyService.clear(userId);

    return '操作成功';
  }

  // 标记已读
  @Post('read')
  async markRead(@Req() req: any, @Body() body: any) {
    const { userId } = req.user || {};
    const { ids } = body;

    await this.notifyService.read(
      userId.toString(),
      ids.split(',').filter(Boolean),
    );

    return '操作成功';
  }
}
